package com.tcp2.net;


import com.tcp2.server.DxsConfig;
import com.tcp2.server.MessageDispatcher;
import com.tcp2.server.ProtoConstants;
import com.tcp2.server.ProtoMsg;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Author: 杨俊辉
 * Time: 2014-09-23 10:53
 * Copyright (C) 2014 Xiamen Yaxon Networks CO.,LTD.
 */
@ChannelHandler.Sharable
public class SlaveLinkHandler extends ChannelInboundHandlerAdapter {

    protected static Logger logger = LoggerFactory.getLogger(SlaveLinkHandler.class);

    private SlaveLink slaveLink;
    private MessageDispatcher messageDispatcher;
    private DxsConfig dxsConfig;
    private AtomicInteger snGen = new AtomicInteger(0);

    public SlaveLinkHandler(SlaveLink slaveLink,
                             MessageDispatcher messageDispatcher,
                             DxsConfig dxsConfig) {
        this.slaveLink = slaveLink;
        this.messageDispatcher = messageDispatcher;
        this.dxsConfig = dxsConfig;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("[{}]从链路连接已建立,下级平台接入码：{}", ctx.channel().remoteAddress(), slaveLink.getGnssCenterId());
        slaveLink.connnected(ctx.channel());
        sendConnectReq(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("[{}]从链路连接已断开,下级平台接入码：{}", ctx.channel().remoteAddress(), slaveLink.getGnssCenterId());
        slaveLink.disconnected();
        //关闭主链路
        try {
          /*  Integer gnssCenterId = slaveLink.getGnssCenterId();
            ConcurrentMap<Integer, PlatformChannel> plat2channelMap = PlatformMap.getPlat2channelMap();
            PlatformChannel platformChannel = plat2channelMap.get(gnssCenterId);
            if (platformChannel != null){
                platformChannel.disconnected(platformChannel.getChannel());
                plat2channelMap.remove(gnssCenterId);
            }*/

        } catch (Exception e){
            logger.info("[{}]从链路断开,主链路断开异常，下级平台接入码：{}", ctx.channel().remoteAddress(), slaveLink.getGnssCenterId());
        }


    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.warn("[{}]从链路连接异常，即将关闭从链路连接,下级平台接入码：{}", ctx.channel().remoteAddress(), slaveLink.getGnssCenterId(),cause);
        slaveLink.closeConnect();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            ProtoMsg m = (ProtoMsg) msg;
            switch (m.msgId) {
                case ProtoConstants.DOWN_CONNECT_RSP:
                    doDownConnectRsp(m);
                    break;
                case ProtoConstants.DOWN_LINKTEST_RSP:
                    doDownLinkTestRsp(m);
                    break;
                default:
                    messageDispatcher.receiveMessage(m);
                    break;
            }
        } catch (Exception e) {
            logger.info("处理从链路的下行消息异常,下级平台接入码：{}",slaveLink.getGnssCenterId(), e);
        }
    }

    /**
     * 处理从链路连接应答
     */
    private void doDownConnectRsp(ProtoMsg msg) {
        logger.info("<- 收到从链路连接应答,下级平台接入码：{}",slaveLink.getGnssCenterId());

        ByteBuf msgData = msg.msgData;
        byte rc = msgData.readByte();
        if (rc == 0) {
            logger.info("从链路连接成功,下级平台接入码：{}",slaveLink.getGnssCenterId());
            slaveLink.authenticated();
            ////////////////////////
     /*       ConcurrentMap<Integer, SlaveLink> gov2platMap = PlatformMap.getGov2platMap();
            SlaveLink sk= gov2platMap.get(12345678);

            ProtoMsg pm=new ProtoMsg();
            pm.msgId = ProtoConstants.DOWN_DISCONNECT_REQ;
            ByteBuf resd = Unpooled.buffer(4);
            resd.writeByte(0x00001);
            //resd.writeBytes(new byte[4]);
            pm.msgData = resd;
            sk.sendMessage(pm);*/

        } else {
            String errMsg = null;
            switch (rc) {
                case 0x01:
                    errMsg = "VERIFY_CODE 错误";
                    break;
                case 0x02:
                    errMsg = "资源紧张，稍后再连接（已经占用）";
                    break;
                case 0x03:
                    errMsg = "其他";
                    break;
                default:
                    errMsg = "从链路连接失败：未知异常";
                    break;
            }
            logger.warn(errMsg);
            if (rc == 0x05) {
                slaveLink.closeConnect();
            } else {
                slaveLink.stop();
            }
        }
    }


    /**
     * 处理从链路连接保持应答
     */
    private void doDownLinkTestRsp(ProtoMsg msg) {
        logger.info("-> 收到从链路连接保持应答,下级平台接入码：{}",slaveLink.getGnssCenterId());
        slaveLink.checkAlive();
    }


    /**
     * 发送从链路连接请求
     */
    private void sendConnectReq(Channel channel) {
        logger.info("<- 发送从链路连接请求..,下级平台接入码：{}",slaveLink.getGnssCenterId());

        ProtoMsg msg = new ProtoMsg();
        msg.msgId = ProtoConstants.DOWN_CONNECT_REQ;

        ByteBuf buf = Unpooled.buffer();
        buf.writeInt(slaveLink.getVerifyCode());
        msg.msgData = buf;

        sendMessage(channel, msg).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture cf) throws Exception {
                if (!cf.isSuccess()) {
                    logger.warn("发送从链路连接请求异常,下级平台接入码：{}",slaveLink.getGnssCenterId(), cf.cause());
                    slaveLink.closeConnect();
                }
            }
        });
    }



    /**
     * 发送从链路连接保持请求
     */
    protected ChannelFuture sendLinkTestReq(Channel channel) {
        logger.info("<- 发送从链路连接保持请求..,下级平台接入码：{}",slaveLink.getGnssCenterId());

        ProtoMsg msg = new ProtoMsg();
        msg.msgId = ProtoConstants.DOWN_LINKTEST_REQ;
        msg.msgData = Unpooled.buffer(0);

        return sendMessage(channel, msg);
    }

    /**
     * 获取下一个流水号
     *
     * @return
     */
    private int nextSn() {
        return snGen.incrementAndGet();
    }

    protected ChannelFuture sendMessage(Channel channel, ProtoMsg msg) {
        msg.msgSn = nextSn();
        messageDispatcher.sn=msg.msgSn;
        return channel.writeAndFlush(msg);
    }
}
